/*
 * Copyright (c) 2018, apexes.net. All rights reserved.
 *
 *         http://www.apexes.net
 *
 */
package net.apexes.commons.lang;

import java.nio.ByteBuffer;
import java.util.UUID;

/**
 * @author <a href=mailto:hedyn@foxmail.com>HeDYn</a>
 */
public final class IDs {

    private IDs() {
    }

    /**
     * 返回一个指定命名空间的ID生成器
     *
     * @param major 命名空间主序号
     * @param minor 命名空间次序号
     * @return 返回一个指定命名空间的ID生成器
     */
    public static IDGenerator idGenerator(int major, short minor) {
        return IDGenerator.namespace(major, minor);
    }

    /**
     * 返回一个指定命名空间的ID生成器
     *
     * @param namespace 命名空间
     * @return 返回一个指定命名空间的ID生成器
     */
    public static IDGenerator idGenerator(long namespace) {
        return IDGenerator.namespace(namespace);
    }

    /**
     * 生成一个长度为22字节的ID
     *
     * @return 返回长度为22字节的ID
     */
    public static String newId() {
        return IDGenerator.genId();
    }

    /**
     * 生成一个长度不超过17字节的ObjectId字符串
     *
     * @return 返回长度不超过17字节的ObjectId字符串
     */
    public static String newObjectId() {
        return Base58.encode(ObjectId.get().toByteArray());
    }

    /**
     * 用指定的文本的md5并生成一个长度为22字节的ID
     * @param text 要进行md5计算的字符串
     * @return 返回长度为22字节的ID
     */
    public static String md5Id(String text) {
        return toBase58Id(Secrets.md5(text));
    }

    /**
     * 随机生成一个长度为22字节的UUID字符串
     *
     * @return 返回长度为22字节的UUID字符串
     */
    public static String randomBase58UUID() {
        return toBase58UUID(UUID.randomUUID());
    }

    /**
     * 获取UUID的字节数组。此方法与<code>{@link #toUUID(byte[])}</code>互逆
     *
     * @param uuid UUID对象
     * @return 返回uuid的字节数组
     */
    public static byte[] toByteArray(UUID uuid) {
        ByteBuffer buf = ByteBuffer.allocate(16);
        buf.putLong(uuid.getMostSignificantBits());
        buf.putLong(uuid.getLeastSignificantBits());
        return buf.array();
    }

    /**
     * 将字节数组转成UUID。此方法与 <code>{@link #toByteArray(UUID)}</code> 互逆
     *
     * @param byteArray 字节数据
     * @return 返回字节数组转成的UUID
     */
    public static UUID toUUID(byte[] byteArray) {
        assert byteArray.length == 16;
        ByteBuffer buf = ByteBuffer.wrap(byteArray);
        long msb = buf.getLong();
        long lsb = buf.getLong();
        return new UUID(msb, lsb);
    }

    /**
     * 将UUID转成使用Base58编码的22字节字符串。此方法与 <code>{@link #formBase58UUID(String)}</code> 互逆
     *
     * @param uuid UUID对象
     * @return 返回使用Base58编码的UUID字符串
     */
    public static String toBase58UUID(UUID uuid) {
        return toBase58Id(toByteArray(uuid));
    }

    /**
     * 将Base58编码的UUID字符串转为UUID对象。此方法与 <code>{@link #toBase58UUID(UUID)}</code> 互逆
     *
     * @param base58UUID 使用Base58编码的22字节字符串
     * @return 返回UUID对象
     */
    public static UUID formBase58UUID(String base58UUID) {
        return toUUID(fromBase58Id(base58UUID));
    }

    static String toBase58Id(byte[] bytes) {
        assert bytes.length == 16;
        String base58Id = Base58.encode(bytes);
        while (base58Id.length() < 22) {
            base58Id = "0" + base58Id;
        }
        return base58Id;
    }

    static byte[] fromBase58Id(String base58Id) {
        assert base58Id.length() == 22;
        while (base58Id.charAt(0) == '0') {
            base58Id = base58Id.substring(1);
        }
        return Base58.decode(base58Id);
    }

}
